package sfsoftware.game;

import java.awt.Font;
import java.io.*;
import java.util.Collections;
import java.util.Properties;
import java.util.prefs.Preferences;

import org.lwjgl.input.*;
import org.lwjgl.LWJGLException;
import org.lwjgl.openal.AL;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;

import org.lwjgl.opengl.GL20;
import org.newdawn.slick.Color;
import org.newdawn.slick.TrueTypeFont;
import org.newdawn.slick.openal.SoundStore;

import sfsoftware.game.actor.enemy.EnergyOrb;
import sfsoftware.game.actor.enemy.ScubaShooter;
import sfsoftware.game.actor.item.Item;
import sfsoftware.game.trevor.*;
import sfsoftware.game.trevor.ui.Dialog;
import sfsoftware.game.trevor.ui.MainMenu;
import sfsoftware.util.*;
import sfsoftware.util.graphics.FloatingText;
import sfsoftware.util.graphics.Graphics;
import sfsoftware.util.graphics.Particle;
import sfsoftware.util.graphics.RGBA;
import sfsoftware.util.graphics.Sprite;
import sfsoftware.util.input.Gamepad;
import sfsoftware.util.input.Kboard;
import sfsoftware.util.map.MapReader;
 
public class TrevorLegacy {	

	private static TrevorLegacy game = new TrevorLegacy();
	
	public static void main(String[] argv) {		
		game.start();
	}
	
	Preferences prefs = Preferences.userNodeForPackage(sfsoftware.game.TrevorLegacy.class);
	private static int ambientShader;
	private static Properties properties = new Properties();	
	private static final String WINDOW_TITLE;
	private static final int PLAYING_FIELD_WIDTH = 16; //9 originally
	private static final int PLAYING_FIELD_HEIGHT = 10; // 8 originally	
	private static final int TILE_SIZE = 40;
	
	private int playingFieldX = 320 - ((PLAYING_FIELD_WIDTH * TILE_SIZE) / 2);
	private int playingFieldY = 0; //240 - ((PLAYING_FIELD_HEIGHT * TILE_SIZE) / 2);
	
	private RGBA borderColor = new RGBA(1, 1, 1, 1);
	private float lifeBarDisplayWidth = 128;
	
	public static Tile[][] tileMap = new Tile[PLAYING_FIELD_WIDTH][PLAYING_FIELD_HEIGHT];
	private static Tile[][][] layer = new Tile[1][PLAYING_FIELD_WIDTH][PLAYING_FIELD_HEIGHT];
	
	private static int mapX = 0;	
	private static int mapY = 17;	
	public static int HUDy = 410; 	
	private static int HUDRuples = 0;
	
	public static int currentItemSelection = 0;
	public static Player player;
	public static boolean bossFight = false;
	
	public static long gameCounter = 0;
	public static boolean vsync = false;
	
	public static enum states 
	{
		INTRO, TITLE_SCREEN, INGAME, GAMEOVER, CREDITS;
	}
	
	private TrueTypeFont font = null;
	private TrueTypeFont smallFont = null;
	private TrueTypeFont bigFont = null;
	
	boolean leftPressed = false;
	boolean rightPressed = false;
	boolean keyPressed = false;
	
	public static boolean isPaused = false;	
	private static states GameState = states.TITLE_SCREEN;	
	private static boolean running = true;
	
	private static int shaderProgram = 0;
	
	static 
	{		
		try 
		{
            //load a properties file
			properties.load(new FileInputStream("res/game.properties"));								
		} 
		catch (IOException ex) 
		{			
			ex.printStackTrace();
		} 		
		
		WINDOW_TITLE = properties.getProperty("window.title");	
	}
	
	private static void drawDisplayBufferZoom(float zoom)
	{
		int playerCenterX = (int) (Player.getXPos() + (Player.getPlayer().getWidth() / 2));
		int playerCenterY = (int) (Player.getYPos() + (Player.getPlayer().getHeight() / 2));	
		
		int width = 640;
		int height = 480;
		int srcWidth = (int) (width / zoom);
		int srcHeight = (int) (height / zoom);	

		int srcX = MathUtils.ensureRange(playerCenterX - (srcWidth / 2), 0, width - srcWidth);
		int srcY = MathUtils.ensureRange(playerCenterY - (srcHeight / 2), 0, Math.max(0, (height - 40) - srcHeight));
		
		Graphics.drawDisplayBuffer(0, 0, 640, 480, srcX, srcY, srcWidth, srcHeight);				
	}
	
	private static void fadeIn(int steps, boolean zoom)
	{
		Graphics.setBuffer(null, true);
		
		int bufferWidth = 640;
		int bufferHeight = 480;		
		double s = (Math.PI / 2) / steps;
		for(double d = (Math.PI / 2); d > 0; d = d - s)
		{
			Graphics.clear();
			SoundStore.get().poll(0);
			// Fade in music!
			Sound.setMusicVolume(Math.min(getPreferences().getFloat("musicvolume", 1.0f), (float) Math.sin(d + (Math.PI / 2))));			
			
			// Zoom screen		
			if(zoom)
			{
				bufferWidth = (int) (640 * (Math.sin(d + (Math.PI / 2))));
				bufferHeight = (int) (480 * (Math.sin(d + (Math.PI / 2))));
			}
			Graphics.drawDisplayBuffer(320 - (bufferWidth / 2), 240 - (bufferHeight / 2), bufferWidth, bufferHeight);						
			Graphics.drawQuad(0, 0, 640, 480, new RGBA(0, 0, 0, (float) Math.sin(d)));			
	      	
			switch (GameState) 
	      	{
	      		case INGAME:	
	      			game.updateHUD();
	      			Dialog.updateDialog();
	      			break;
	      		default:
	      			break;
	      	}	
			
			Display.update();
			Display.sync(60);
		}
	}
	
	private static void fadeOut(int steps, boolean zoom)
	{		
		int bufferWidth = 640;
		int bufferHeight = 480;		
		double s = (Math.PI / 2) / steps;
		
		for(double d = 0; d <= (Math.PI / 2); d = d + s) //0.025)
		{		
			Graphics.clear();
			
			SoundStore.get().poll(0);
			// Fade out music!			
			Sound.setMusicVolume(Math.min(getPreferences().getFloat("musicvolume", 1.0f), (float) Math.sin(d + (Math.PI / 2))));
			
			// Zoom screen		
			if(zoom)
			{
				bufferWidth = (int) (640 * (Math.sin(d + (Math.PI / 2))));
				bufferHeight = (int) (480 * (Math.sin(d + (Math.PI / 2))));
			}
						
			Graphics.drawDisplayBuffer(320 - (bufferWidth / 2), 240 - (bufferHeight / 2), bufferWidth, bufferHeight);						
			Graphics.drawQuad(0, 0, 640, 480, new RGBA(0, 0, 0, (float) Math.sin(d)));
			
	      	switch (GameState) 
	      	{
	      		case INGAME:	
	      			game.updateHUD();
	      			Dialog.updateDialog();
	      			break;
	      		default:
	      			break;
	      	}
			
			Display.update();
			Display.sync(60);
		}		
	}
	
	private void drawLoadScreen(java.util.ArrayList<String> al, TrueTypeFont ttf)
	{
		Graphics.clear();
		
		int size = al.size();
		for(String s : al)
		{
			ttf.drawString(35, 420 - (ttf.getHeight() * (size - 1)), s);
			size--;
		}
		Graphics.drawQuad(0, 0, 640, 240, 0, 0, 0, 1);
		Graphics.drawQuad(0, 240, 640, 240, new RGBA(0,0,0,1), new RGBA(0,0,0,1), new RGBA(0,0,0,0), new RGBA(0,0,0,0));
		Display.update();
	}
	
	public void init()
	{				
		// Loading screen
		Font awtFont = new Font("Verdana", Font.BOLD, 20);
		TrueTypeFont loadingFont = new TrueTypeFont(awtFont, true);			
		java.util.ArrayList<String> loadingText = new java.util.ArrayList<String>();
		
		loadingText.add("Loading Trevor Legacy...");
		drawLoadScreen(loadingText, loadingFont);
				
		// The new default font...
		awtFont = new Font("Verdana", Font.PLAIN, 12);
		font = new TrueTypeFont(awtFont, true);
		
		awtFont = new Font("Verdana", Font.PLAIN, 9);
		smallFont = new TrueTypeFont(awtFont, true);			
		

		awtFont = new Font("Verdana", Font.PLAIN, 20);
		bigFont = new TrueTypeFont(awtFont, true);
		
		loadingText.add("Initializing game engine...");
		drawLoadScreen(loadingText, loadingFont);
		
		// Position the tiles
		for(int i = 0; i < PLAYING_FIELD_WIDTH; i++)
		{
			for(int j = 0; j < PLAYING_FIELD_HEIGHT; j++)
			{		
				tileMap[i][j] = new Tile(playingFieldX + (i * TILE_SIZE), playingFieldY + (j * TILE_SIZE), "tiles1", true);				
				for(int n = 0; n < layer.length; n++)
				{
					layer[n][i][j] = new Tile(playingFieldX + (i * TILE_SIZE), playingFieldY + (j * TILE_SIZE), "", true);
				}
			}
		}	
		
		loadingText.add("Reticulating splines...");
		drawLoadScreen(loadingText, loadingFont);		
		loadingText.add("Loading textures...");
		drawLoadScreen(loadingText, loadingFont);
		
		// Load textures and audio into memory
		Graphics.loadTextures();
		
		loadingText.add("Loading audio...");
		drawLoadScreen(loadingText, loadingFont);
		Sound.loadAudio();

		Actor.setPlayingField(playingFieldX, playingFieldY);		
	}
	
	public static void initMap(int mapX, int mapY)
	{
		// Clear all actors and particles... things that shouldn't exist after we leave the room!
		Actor.cast.removeAllElements();
		Particle.removeAll();
		
		tileMap = MapReader.loadBaseTiles(tileMap, mapX, mapY);
		layer = MapReader.loadLayers(layer, mapX, mapY);		
		
		MapReader.loadActors(mapX, mapY);
		MapReader.loadItems(mapX, mapY);
	}
 
	public static Preferences getPreferences()
	{
		return game.prefs;
	}
	
	public static void newGame()
	{				
		fadeOut(63, false);
		Sound.stopMusic();					
		Sound.setMusicVolume(Math.min(getPreferences().getFloat("musicvolume", 1.0f), 1.0f));
		
		String playerTexture = properties.getProperty("player.texture", "player");	    					
		TrevorLegacy.player = new Player(390, 270, playerTexture, 40, 40);	    							
		initMap(mapX, mapY);
		TrevorLegacy.setGameState(TrevorLegacy.states.INGAME);
	}
	
	public void pollInput() {    	
		Gamepad.poll();
    	
		switch (GameState) 
    	{
  			case TITLE_SCREEN:
  				MainMenu.pollInput();
  				break;
    		case GAMEOVER:
    			if(Gamepad.buttonPressed(Gamepad.BUTTON_A) || Kboard.keyPressed(Keyboard.KEY_SPACE) || Kboard.keyPressed(Keyboard.KEY_ESCAPE))
    			{    				
    				Sound.stopMusic();
	        		GameState = states.TITLE_SCREEN;
    			}
    			break;
	    	case INGAME:	    		
	    		Player.keyDown = false;	 
	    		
	    		if(Kboard.keyPressed(Keyboard.KEY_F))
	    		{
	    			//transitionTest();
	    			fadeOut(63, true);
	    			fadeIn(158, true);
	    		}
	    		
	    		// For testing
	    		if(Kboard.keyPressed(Keyboard.KEY_T))
	    		{
	    			//new Angler(256, 100, "angler", 84, 150, tileMap);	    			
	    			//Player.getInventory().add("strength ring");	    			
	    			//new sfsoftware.game.actor.PushableObject(300, 220, "objects", 0, 40, 40, 40);	    			
	    			//new ScubaShooter(100, 52, "shooter", 20, 36, TrevorLegacy.tileMap);
	    			new EnergyOrb(100,100, null, 32, 32, EnergyOrb.CLOCKWISE, TrevorLegacy.tileMap);
	    		}
	    		if(Kboard.keyPressed(Keyboard.KEY_Y))
	    		{
	    			Player.getInventory().add("wiffa");	    		
	    			Player.getInventory().add("map");	    			
    				Player.getInventory().add("toxic powder");
    				Player.getInventory().add("snow dust");
    				Player.getInventory().add("bomb");
	    			
	    			mapX = 4;
	    			mapY = 2;
	    			initMap(mapX, mapY);	    			
	    		}
	    		
	    		if(Kboard.keyPressed(Keyboard.KEY_ESCAPE) || Gamepad.buttonPressed(Gamepad.BUTTON_BACK))
	    		{
	    			// Exit to main menu!
	    			fadeOut(20, false);	    			
	    			Sound.stopMusic();
	    			Sound.setMusicVolume(Math.min(getPreferences().getFloat("musicvolume", 1.0f), 1.0f));
    		    	GameState = states.TITLE_SCREEN;
	    		}
	    		else if((Kboard.keyPressed(Kboard.pauseKeys) || Gamepad.buttonPressed(Gamepad.BUTTON_START)) && !(Dialog.displayDialog))
	    		{
	    			isPaused = !isPaused;
	    			if(isPaused) 
	    			{
	    				Sound.playSound("pause_on");
	    			}
	    			else
	    			{
	    				Sound.playSound("pause_off");
	    			}
	    		}
	    		else if(!isPaused && !(Dialog.displayDialog))
	    		{		
	    			// Wiffa!!
	    			if((Gamepad.buttonPressed(Gamepad.BUTTON_A) || Kboard.keyPressed(Keyboard.KEY_SPACE)))
	    			{	    				
	    				if(Player.getInventory().contains("Wiffa"))
		    			{
	    					player.useWiffa();	
		    			}
		    			else
		    			{	    			
		    				Sound.playSound("nono");
		    			}	    				
	    			}
	    			
	    			
	    			if(Gamepad.buttonPressed(Gamepad.BUTTON_B) || Kboard.keyPressed(Keyboard.KEY_LCONTROL))
	    			{
	    				player.useCurrentItem();
	    			}
	    			
	    			// Sprinting! Should this require an item? Probably!
	    			if(Kboard.isKeyDown(Keyboard.KEY_LSHIFT) || Gamepad.isButtonDown(Gamepad.BUTTON_X))
	    			{
	    				Player.setPlayerSpeed(3);
	    			}
	    			else
	    			{
	    				Player.setPlayerSpeed(2);
	    			}
	    			
			    	if(Kboard.isKeyDown(Kboard.leftKeys) || Gamepad.xAxisLeft())
			    	{		    					    	
			    		player.move(-1, 0, tileMap);	
			    		// Room change
			    	 	if(player.getX() < (tileMap[0][0].getX() + 20) && !bossFight)
			    	 	{
			    	 		// Relocate the player
			    	 		player.move(tileMap[PLAYING_FIELD_WIDTH - 1][0].getX() + 20, player.getY());
			    	 		mapX--;
			    	 		initMap(mapX, mapY);
			    	 	}			    	
			    	}
			    	if(Kboard.isKeyDown(Kboard.downKeys) || Gamepad.yAxisDown())
			    	{
		    			player.move(0, 1, tileMap);
			    		// Room change
			    	 	if(player.getY() > (tileMap[0][PLAYING_FIELD_HEIGHT - 1].getY() + 20)  && !bossFight)
			    	 	{
			    	 		// Relocate the player    	 		
			    	 		player.move(player.getX(), tileMap[0][0].getY() - 20);
			    	 		mapY++;
			    	 		initMap(mapX, mapY);
			    	 	}		    		
			    	}
			    	if(Kboard.isKeyDown(Kboard.rightKeys) || Gamepad.xAxisRight())
			    	{		    					    	
			    		player.move(1, 0, tileMap);
			    		// Room change
			    	 	if(player.getX() > (tileMap[PLAYING_FIELD_WIDTH - 1][0].getX() + 20)  && !bossFight)
			    	 	{
			    	 		// Relocate the player
			    	 		player.move(tileMap[0][0].getX() - 20, player.getY());
			    	 		mapX++;
			    	 		initMap(mapX, mapY);
			    	 	}  			    		
			    	}    	
			    	if(Kboard.isKeyDown(Kboard.upKeys) || Gamepad.yAxisUp())
			    	{
		    		 	player.move(0, -1, tileMap);	
			    	 	// Room change
			    	 	if(player.getY() < (tileMap[0][0].getY() - 20)  && !bossFight)
			    	 	{
			    	 		// Relocate the player
			    	 		player.move(player.getX(), tileMap[0][PLAYING_FIELD_HEIGHT - 1].getY() + 20);
			    	 		mapY--;
			    	 		initMap(mapX, mapY);
			    	 	}			    		
			    	} 
	    		}
	    		else if(isPaused) 
	    		{	    			
	    			// Keyboard input during pause menu!
	        		if (Kboard.keyPressed(Kboard.leftKeys) || Gamepad.povXLeftPressed() || Gamepad.xAxisLeftPressed()) 
	        		{
	        			if(currentItemSelection > 0)
	        			{
	        				Sound.playSound("menu_sel");
	        				currentItemSelection--;
	        				//Player.setCurrentItem((Player.getInventory(Item.USEABLE).toArray())[currentItemSelection].toString());
	        				Player.setCurrentItem((Item) (Player.getInventory(Item.USEABLE).toArray())[currentItemSelection]);
	        			}
	        		}
	        		else if (Kboard.keyPressed(Kboard.rightKeys) || Gamepad.povXRightPressed() || Gamepad.xAxisRightPressed()) 
	        		{
	        			if(currentItemSelection < Player.getInventory(Item.USEABLE).size() - 1)
	        			{
	        				Sound.playSound("menu_sel");
	        				currentItemSelection++;
	        				//Player.setCurrentItem((Player.getInventory(Item.USEABLE).toArray())[currentItemSelection].toString());
	        				Player.setCurrentItem((Item) (Player.getInventory(Item.USEABLE).toArray())[currentItemSelection]);
	        			}
	        		}
	        		else if (Kboard.keyPressed(Kboard.downKeys) || Gamepad.povYDownPressed() || Gamepad.yAxisDownPressed()) 
	        		{
	        			if(currentItemSelection + 7 <= Player.getInventory(Item.USEABLE).size() - 1)
	        			{
	        				Sound.playSound("menu_sel");
	        				currentItemSelection = currentItemSelection + 7;
	        				//Player.setCurrentItem((Player.getInventory(Item.USEABLE).toArray())[currentItemSelection].toString());
	        				Player.setCurrentItem((Item) (Player.getInventory(Item.USEABLE).toArray())[currentItemSelection]);
	        			}
	        			else if(Player.getInventory(Item.USEABLE).size() > 7)
	        			{
	        				Sound.playSound("menu_sel");
	        				currentItemSelection = Player.getInventory(Item.USEABLE).size() - 1;
	        				//Player.setCurrentItem((Player.getInventory(Item.USEABLE).toArray())[currentItemSelection].toString());
	        				Player.setCurrentItem((Item) (Player.getInventory(Item.USEABLE).toArray())[currentItemSelection]);
	        			}
	        		}
	        		else if (Kboard.keyPressed(Kboard.upKeys) || Gamepad.povYUpPressed() || Gamepad.yAxisUpPressed()) 
	        		{
	        			if(currentItemSelection >= 7)
	        			{
	        				Sound.playSound("menu_sel");
	        				currentItemSelection = currentItemSelection - 7;
	        				//Player.setCurrentItem((Player.getInventory(Item.USEABLE).toArray())[currentItemSelection].toString());
	        				Player.setCurrentItem((Item) (Player.getInventory(Item.USEABLE).toArray())[currentItemSelection]);	        				
	        			}
	        		}
	    		}
	    		else if(Dialog.displayDialog)
	    		{
	    			Dialog.pollDialogInput();
	    		}
		    	break;
			default:
				break;
		}    
    	// Store the current state so we can check against it later
		Kboard.storeKBState();
		Gamepad.storeGamepadState();
	}

	/**
	 * Set the display mode to be used 
	 * 
	 * @param width The width of the display required
	 * @param height The height of the display required
	 * @param fullscreen True if we want fullscreen mode
	 */
	public static void setDisplayMode(int width, int height, boolean fullscreen) {

	    // return if requested DisplayMode is already set
	    if ((Display.getDisplayMode().getWidth() == width) && 
	        (Display.getDisplayMode().getHeight() == height) && 
		(Display.isFullscreen() == fullscreen)) {
		    return;
	    }

	    try {
	        DisplayMode targetDisplayMode = null;
			
		if (fullscreen) {
		    DisplayMode[] modes = Display.getAvailableDisplayModes();
		    int freq = 0;
					
		    for (int i=0;i<modes.length;i++) {
		        DisplayMode current = modes[i];
						
			if ((current.getWidth() == width) && (current.getHeight() == height)) {
			    if ((targetDisplayMode == null) || (current.getFrequency() >= freq)) {
			        if ((targetDisplayMode == null) || (current.getBitsPerPixel() > targetDisplayMode.getBitsPerPixel())) {
				    targetDisplayMode = current;
				    freq = targetDisplayMode.getFrequency();
	                        }
	                    }

			    // if we've found a match for bpp and frequence against the 
			    // original display mode then it's probably best to go for this one
			    // since it's most likely compatible with the monitor
			    if ((current.getBitsPerPixel() == Display.getDesktopDisplayMode().getBitsPerPixel()) &&
	                        (current.getFrequency() == Display.getDesktopDisplayMode().getFrequency())) {
	                            targetDisplayMode = current;
	                            break;
	                    }
	                }
	            }
	        } else {
	            targetDisplayMode = new DisplayMode(width,height);
	        }

	        if (targetDisplayMode == null) {
	            System.out.println("Failed to find value mode: "+width+"x"+height+" fs="+fullscreen);
	            return;
	        }

	        Display.setDisplayMode(targetDisplayMode);
	        Display.setFullscreen(fullscreen);
				
	    } catch (LWJGLException e) {
	        System.out.println("Unable to setup mode "+width+"x"+height+" fullscreen="+fullscreen + e);
	    }
	}	

	public static void setGameState(states newState)
	{
		GameState = newState;
	}
	
	public static void setRunning(boolean r)
	{
		running = r;
	}
	
	/**
	 * Start the game
	 */
	public void start() 
	{
		System.out.println("Trevor Legacy, (c) S&F Software, 2014");
		Graphics.setAppIcon("res/graphics/icon16.png", "res/graphics/icon32.png");
		Graphics.initGL(640, 480, "Trevor Legacy");					
		Graphics.setDisplayMode(640, 480, prefs.getBoolean("fullscreen", false));
		vsync = prefs.getBoolean("vsync", false);
		Mouse.setGrabbed(Display.isFullscreen());
		
		init();						
		
		// Load sound and music preferences
		Sound.setSoundEffectVolume(prefs.getFloat("soundvolume", 1.0f));
		Sound.setMusicVolume(prefs.getFloat("musicvolume", 1.0f));
		
		SoundStore.get().poll(0);		
		//updateLogo();

		
		GameState = states.TITLE_SCREEN;						
		while (running) {			
			
			Graphics.clear();
			
	      	switch (GameState) 
	      	{
	      		case INTRO:
		    	
	      		case TITLE_SCREEN:
	      			if(!(Sound.isMusicPlaying()))
	      			{
	      				Sound.playMusic("theme", true);
	      			}
	      			
	      			Graphics.setBuffer(Graphics.getDisplayBuffer(), true);
	      			
	      			MainMenu.update();	  
	      			
	      			Graphics.drawDisplayBuffer(0, 0, 640, 480);
	      			Graphics.setBuffer(null);
	      			
	      			break;
	      		case INGAME:		
	      			if(!(Sound.isMusicPlaying()))
	      			{
	      				// For now, play a randomized tune... getting tired of the same song while testing...
	      				Sound.playMusic(); //("woods", true);	      			
	      			}
	      			
	      			// Game over if they run out of health!
					if(Player.getHealth() <= 0)	
					{
						Sound.playMusic("gameover");
						GameState = states.GAMEOVER;
					}
					
					//Graphics.getDisplayBuffer().setCurrentShader(Graphics.shaderProgram);
					Graphics.setBuffer(Graphics.getDisplayBuffer(), true);
					
					updatePlayingField(0);		
					Actor.updateCast();								
					player.update();	
					updatePlayingField(1);
					Particle.updateAll();										
					
					FloatingText.updateAll();
					Graphics.drawDisplayBuffer(0, 0, 640, 480);
					//drawDisplayBufferZoom(1.25f);					
					Graphics.setBuffer(null);
					
					updateHUD();
					Dialog.updateDialog();	
					Script.updateRunningScripts();					
					break;
		    	case GAMEOVER:
					Graphics.drawQuad(0, 0, 640, 480, 0.7f, 0, 0, 1);
					player.update();
					bigFont.drawString(320 - (bigFont.getWidth("GAME OVER") / 2), 200, "GAME OVER");
					break;
		    	default:
		    		break;
			}
			
			Clock.update();
						
			Display.update();
			Display.sync(60); 
			
			pollInput();
			SoundStore.get().poll(0);			
			
			if (Display.isCloseRequested()) 
			{
				Display.destroy();
				AL.destroy();
				System.exit(0);
			}							
		}
		//fadeOut(10, false);
		Display.destroy();
		AL.destroy();
		System.out.println("Bye, bye!");
		System.exit(0);
	}
	
	private void updateHUD()
	{		
		// HUD background
		int playingFieldBottom = playingFieldY + (PLAYING_FIELD_HEIGHT * 40);
		int playingFieldRight = playingFieldX + (PLAYING_FIELD_WIDTH * 40);
		
		Graphics.drawQuad(0, 0, 640, playingFieldY, 0, 0, 0, 1);
		Graphics.drawQuad(0, 0, playingFieldX, 480, 0, 0, 0, 1);		
		Graphics.drawQuad(playingFieldRight, 0, 640 - playingFieldRight, 480, 0, 0, 0, 1);
		Graphics.drawQuad(0, playingFieldBottom, 640, 480 - playingFieldBottom, 0, 0, 0, 1);
		
		RGBA bgTop = new RGBA(0.1f, 0.2f, 0.3f, 0.75f); //new RGBA(0, 0, 0, 0.65f);
		RGBA bgBottom = new RGBA(0, 0, 0, 0.95f);
		Graphics.drawQuad(0, HUDy - 10, 640, 480 - HUDy, bgTop, bgTop, bgBottom, bgBottom);		

		// Life bar! 32
		smallFont.drawString(142, HUDy, "LIFE:");
		Graphics.drawRect(174, HUDy, 132, 12, borderColor, 2);
		
		RGBA redTop = new RGBA(0.72f, 0, 0, 1);
		RGBA redBottom = new RGBA(0.42f, 0, 0, 1);
		Graphics.drawQuad(176, HUDy + 2, 128, 8, redTop, redTop, redBottom, redBottom);					

		RGBA greenTop = new RGBA(0, 0.72f, 0, 1);
		RGBA greenBottom = new RGBA(0, 0.42f, 0, 1);
		float lifeBarWidth = (((float)Player.getHealth()) / Player.getMaxHealth()) * 128;
		if((int)lifeBarDisplayWidth < (int)lifeBarWidth)
		{
			lifeBarDisplayWidth++;
		}
		else if((int)lifeBarDisplayWidth > (int)lifeBarWidth)
		{
			lifeBarDisplayWidth--;
		}
		Graphics.drawQuad(176, HUDy + 2, lifeBarDisplayWidth, 8, greenTop, greenTop, greenBottom, greenBottom);
		
		Graphics.drawSprite(345, HUDy, "ruple", 16, 16, 64, 0, 16, 16);
		if(Player.getRuples() > HUDRuples)
		{
			HUDRuples++;
		}
		else if(Player.getRuples() < HUDRuples)
		{
			HUDRuples--;
		}
		font.drawString(365, HUDy, String.valueOf(HUDRuples));
		//font.drawString(350, 425, Clock.getFormattedHoursMinutes(gameCounter), Color.white);		
		
		// Space will always be the wiffa
		Graphics.drawQuad(405, HUDy, 40, 40, 0, 0, 0, 0.4f);
		Graphics.drawRect(405, HUDy, 40, 40, borderColor, 2);
		smallFont.drawString(405, HUDy + 42, Kboard.getKeyName(Keyboard.KEY_SPACE));				
		if(Player.getInventory().contains("Wiffa"))
		{
			Sprite s = Inventory.itemSprites.get("wiffa");
			if(s != null)
			{
				s.move(405, HUDy);	
				s.draw(40, 40);
			}
		}
		
		// The Secondary item changes
		Graphics.drawQuad(455, HUDy, 40, 40, 0, 0, 0, 0.4f);
		Graphics.drawRect(455, HUDy, 40, 40, borderColor, 2);
		smallFont.drawString(455, HUDy + 42, Kboard.getKeyName(Keyboard.KEY_LCONTROL));		
		/*Sprite s = Inventory.itemSprites.get(Player.getCurrentItem());
		if(s != null)
		{*/
		if(Player.getCurrentItem() != null)
		{
			Sprite s = Inventory.itemSprites.get(Player.getCurrentItem().toString());
			s.move(455, HUDy);	
			s.draw(40, 40);
		}
		
		if(isPaused || HUDy < 410)
		{	
			// Only display the mini map if they have the map in their inventory!			
			if(Player.getInventory().contains("Map"))
			{
				updateMiniMap(142, HUDy + 200);
			}
			
			// Update the useable inventory!
			Inventory<Item> v = Player.getInventory(Item.USEABLE);
			Item[] inventory = (Item[]) v.toArray(new Item[v.size()]);
			int inventoryY = HUDy + 80;
			int inventoryX = 162;
			
			if(currentItemSelection > inventory.length - 1 && inventory.length > 0)
			{
				currentItemSelection = inventory.length - 1;
			}			
			
			for(int i = 0; i < inventory.length; i++)
			{	
				if(i > 0 && i % 7 == 0)
				{
					inventoryX = 160;
					inventoryY = inventoryY + 40;
				}
				//Graphics.drawQuad(inventoryX, inventoryY, 40, 40, 0.5f, 0.5f, 0.5f, 1);				
				Graphics.drawSprite(inventoryX, inventoryY, inventory[i].getTexture(), 40, 40, inventory[i].getSrcX(), inventory[i].getSrcY(), 40, 40);
				if(currentItemSelection == i)
				{
					Graphics.drawRect(inventoryX, inventoryY, 40, 40, 1, 1, 1, 1, 2);
				}
				inventoryX = inventoryX + 40;
			}

		
			// Update the passive inventory!
			v = Player.getInventory(Item.PASSIVE);
			// Remove the map so it isn't displayed on-screen in the inventory
			// It already takes up enough screen real estate as it is
			if(v.contains("Map"))			
				v.remove("Map");			
			
			inventory = (Item[]) v.toArray(new Item[v.size()]);
			inventoryY = HUDy + 200;
			inventoryX = 340;
			
			for(int i = 0; i < inventory.length; i++)
			{					
				if(i > 0 && i % 4 == 0)
				{
					inventoryX = 340;
					inventoryY = inventoryY + 40;
				}
				
				//Graphics.drawQuad(inventoryX, inventoryY, 40, 40, 0.5f, 0.5f, 0.5f, 1);					
				Graphics.drawSprite(inventoryX, inventoryY, inventory[i].getTexture(), 40, 40, inventory[i].getSrcX(), inventory[i].getSrcY(), 40, 40);				
				/*if(inventory[i].getLuckModifier() > 0)
				{
					smallFont.drawString(inventoryX, inventoryY - 9, "LUCK + " + inventory[i].getLuckModifier());				
				}*/
				
				inventoryX = inventoryX + 40;
			}	
			
			java.text.DecimalFormat statisticFormat = new java.text.DecimalFormat("#.##;#.##");
			java.text.DecimalFormat modifierFormat = new java.text.DecimalFormat("+#.##;-#.##");

			// Draw the damage resistance statistic
			if((Player.getWiffaDamage() - Player.getBaseWiffaDamage()) != 0)
			{
				smallFont.drawString(142, HUDy + 350, "ATTACK: " + statisticFormat.format(Player.getBaseWiffaDamage()) + " (" + modifierFormat.format(Player.getWiffaDamage() - Player.getBaseWiffaDamage()) + ")");
			}
			else
			{
				smallFont.drawString(142, HUDy + 350, "ATTACK: " + statisticFormat.format(Player.getBaseWiffaDamage()));			
			}
			// Draw the damage resistance statistic
			if((Player.getDamageResistance() - Player.getBaseDamageResistance()) != 0)
			{
				smallFont.drawString(142, HUDy + 365, "DAMAGE RESISTANCE: " + statisticFormat.format(Player.getBaseDamageResistance()) + " (" + modifierFormat.format(Player.getDamageResistance() - Player.getBaseDamageResistance()) + ")");
			}
			else
			{
				smallFont.drawString(142, HUDy + 365, "DAMAGE RESISTANCE: " + statisticFormat.format(Player.getBaseDamageResistance()));
			}
			// Draw the luck statistic
			if((Player.getLuck() - Player.getBaseLuck()) != 0)
			{
				smallFont.drawString(142, HUDy + 380, "LUCK: " + statisticFormat.format(Player.getBaseLuck()) + " (" + modifierFormat.format(Player.getLuck() - Player.getBaseLuck()) + ")");
			}
			else
			{
				smallFont.drawString(142, HUDy + 380, "LUCK: " + statisticFormat.format(Player.getBaseLuck()));
			}
		}
		
		if(isPaused)
		{
			
			if(HUDy > playingFieldY + 10)
			{
				HUDy = HUDy - 15;
			}
			else
			{
				HUDy = playingFieldY + 10;
			}
			//font.drawString(8, 8, "Game Paused", Color.white);
		}
		else
		{
			if(HUDy < 410)
			{
				HUDy = HUDy + 15;
			}
			else
			{
				HUDy = 410;
			}
		}
	}
	
	@SuppressWarnings("unused")
	private void updateLogo()
	{
		// Method that runs once to display the opening S&F Software logo
		int logoState = 0;
		int logoWait = 0;
		float logoAlpha = 0;
		
		Sound.playMusic("logo", false);
		
		while (logoState != 2)
		{			
			Graphics.clear();
			
			if(logoState == 0)
			{
				if(logoAlpha < 1)
				{
					logoAlpha = logoAlpha + 0.02f;
				}
				else
				{			
					if(logoWait < 50)
					{
						logoWait++;
					}else
					{
						logoState++;
					}
				}
			}
			else if(logoState == 1)
			{
				if(logoAlpha > 0)
				{
					logoAlpha = logoAlpha - 0.005f;
				}
				else
				{
					logoState++;
				}				
			}
			Graphics.drawSprite(192, 112, "sflogo", 256, 256, 0, 0, 256, 256, 1, 1, 1, logoAlpha);
			
			SoundStore.get().poll(0);
			Display.update();
			Display.sync(60);
		}
		
		Sound.stopMusic();
	}
	
	private void updateMiniMap(int x, int y)
	{				
		// Mini-map - this should only display if the player actually got the map!
		RGBA mapColor = new RGBA(0.956f, 0.925f, 0.839f, 1);
		int miniMapTileSize = 6;
		int miniMapWidth = MapReader.getMapWidth(); //26;
		int miniMapHeight = MapReader.getMapHeight(); // 20;
		smallFont.drawString(x, y, "MAP - " + MapReader.getMapName().toUpperCase());
		Graphics.drawQuad(x, y + 15, miniMapTileSize * 30, miniMapTileSize * 22, 0.1f, 0.1f, 0.1f, 1);
		
		// Reposition X and Y to center the map.
		x = (x + ((miniMapTileSize * 30) / 2)) - ((miniMapTileSize * miniMapWidth + 4) / 2);
		y = (y + ((miniMapTileSize * 22) / 2)) - ((miniMapTileSize * miniMapHeight + 4) / 2);
		
		Graphics.drawRect(x, y + 15, miniMapTileSize * miniMapWidth + 4, miniMapTileSize * miniMapHeight + 4, mapColor, 2);
		
		x = x + 2;
		y = y + 2;
		
		for(int i = 0; i < miniMapWidth; i++)
		{
			for(int j = 0; j < miniMapHeight; j++)
			{
				int miniMapRoomX = (miniMapTileSize * i) + x;
				int miniMapRoomY = (miniMapTileSize * j) + y + 15;
				if(mapX == i && mapY == j)
				{
					Graphics.drawQuad(miniMapRoomX, miniMapRoomY, miniMapTileSize, miniMapTileSize, 0, 0.5f, 0, 1); //0.403f, 0.203f, 0, 1);
				}
				else
				{
					Graphics.drawQuad(miniMapRoomX, miniMapRoomY, miniMapTileSize, miniMapTileSize, mapColor);
				}					
			}
		}	

	}
	
	private void updatePlayingField()
	{
		updatePlayingField(0);
		updatePlayingField(1);
	}
	
	private void updatePlayingField(int pass)
	{
		for(int i = 0; i < PLAYING_FIELD_WIDTH; i++)
		{
			for(int j = 0; j < PLAYING_FIELD_HEIGHT; j++)
			{
				if(pass == 0)
				{
					Graphics.drawSprite(tileMap[i][j].getX(), tileMap[i][j].getY(), tileMap[i][j].getTexture(), TILE_SIZE, TILE_SIZE, tileMap[i][j].getSrcX(), tileMap[i][j].getSrcY(), 40, 40);
				}
				else if(pass == 1)
				{
					for(int n = 0; n < layer.length; n++)
					{
						if(!(layer[n][i][j].getTexture().equals("")))
						{										
							layer[n][i][j].draw(TILE_SIZE, TILE_SIZE, layer[n][i][j].getSrcX(), layer[n][i][j].getSrcY(), TILE_SIZE, TILE_SIZE);										
						}
					}
				}
			}
		}			
	}
	

}